/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use crate::common::constants::*;
use crate::common::types::*;
use crate::utils::parcel::Parcel;
use crate::{Box, Vec, log_e, log_i, singleton_registry};
use crate::traits::user_db_manager::UserDbManager;
use crate::traits::user_db_manager::User;
use crate::traits::user_db_manager::Credential;
use crate::traits::user_db_manager::Enrolled;
use crate::traits::user_db_manager::CredentialFilter;
use crate::traits::user_db_manager::EnrolledIdFilter;
use crate::traits::storage_io::StorageIoRegistry;
use crate::traits::storage_io::StorageType;
use crate::traits::crypto_engine::CryptoEngineRegistry;
use crate::traits::time_keeper::TimeKeeperRegistry; 
use crate::traits::config_manager::ConfigManagerRegistry;
use crate::traits::auth_policy_manager::AuthPolicyManagerRegistry;
use crate::impls::default_config_manager::NO_CHECK_PIN_EXPIRED_PERIOD;

const VERSION_TWO: u32 = 2;
const VERSION_THREE: u32 = 3;
const VERSION_FOUR: u32 = 4;
const VERSION_FIVE: u32 = 5;
const CURRENT_VERSION: u32 = 6;
const IDM_USER_INFO: &str = "userinfo";
const MAX_USER_CREDENTIAL_NUM: u32 = 40;
const ABANDON_PIN_VALID_PERIOD: u64 = 96 * 3600 * 1000;

pub struct DefaultUserDbManager {
    user_infos: Vec<User>,
    credential_infos: Vec<Credential>,
    enrolled_infos: Vec<Enrolled>,
}

impl DefaultUserDbManager {
    pub fn new() -> Self {
        DefaultUserDbManager {
            user_infos: Vec::new(),
            credential_infos: Vec::new(),
            enrolled_infos: Vec::new(),
        }
    }

    fn read_user_info(&mut self, parcel: &mut Parcel) -> Result<i32, ErrorCode> {
        let user_id = parcel.read_i32()?;
        let user_info = User {
            user_id, 
            sec_uid: parcel.read_u64()?, 
            user_type: UserType::try_from(parcel.read_i32()?)?,
            user_state: UserState::UserStateInit
        };
        
        self.user_infos.push(user_info);
        return Ok(user_id)
    }

    fn read_credential_info(&mut self, user_id: i32, db_version: u32, parcel: &mut Parcel) -> Result<(), ErrorCode> {
        let credential_id = CredentialId(parcel.read_u64()?);
        let template_id = TemplateId(parcel.read_u64()?);
        let auth_type = AuthType::try_from(parcel.read_i32()?)?;
        let executor_sensor_hint = parcel.read_u32()?;
        let executor_matcher = parcel.read_u32()?;
        let capability_level = AuthCapabilityLevel::try_from(parcel.read_u32()?)?;
        let credential_type;
        let mut enrolled_sys_time = TimeKeeperRegistry::get().get_ree_time()?;
        let mut abandon_sys_time = TimeKeeperRegistry::get().get_rtc_time()?;
        let mut abandon_flag = false;
        let mut storage_type = CredStorageType::StorageTypeTee;
        match db_version {
            VERSION_THREE => {
                credential_type = CredentialType::try_from(parcel.read_i32()?)?;
            },
            VERSION_FOUR => {
                credential_type = CredentialType::try_from(parcel.read_i32()?)?;
                enrolled_sys_time = parcel.read_u64()?;
            },
            VERSION_FIVE => {
                credential_type = CredentialType::try_from(parcel.read_i32()?)?;
                enrolled_sys_time = parcel.read_u64()?;
                abandon_sys_time = parcel.read_u64()?;
                abandon_flag = parcel.read_u32()? != 0;
            },
            CURRENT_VERSION => {
                credential_type = CredentialType::try_from(parcel.read_i32()?)?;
                enrolled_sys_time = parcel.read_u64()?;
                abandon_sys_time = parcel.read_u64()?;
                abandon_flag = parcel.read_u32()? != 0;
                storage_type = CredStorageType::try_from(parcel.read_u32()?)?;
            }
            _ => {
                log_e!("db_version is error, db_version: {}", db_version);
                return Err(ErrorCode::GeneralError);
            }
        }
        let credential_info = Credential {
            user_id, credential_id, template_id, auth_type, executor_sensor_hint, executor_matcher,
            capability_level, credential_type, enrolled_sys_time, abandon_sys_time, abandon_flag, storage_type
        };
        self.add_credential(user_id, &credential_info)?;
        Ok(())
    }

    fn read_enrolled_info(&mut self, user_id: i32, parcel: &mut Parcel) -> Result<(), ErrorCode> {
        let enrolled_info = Enrolled {
            user_id: user_id,
            enrolled_id: parcel.read_u64()?,
            auth_type: AuthType::try_from(parcel.read_i32()?)?
        };
        self.add_enrolled_id(user_id, &enrolled_info)
    }

    fn write_user_info(&self, parcel: &mut Parcel, user_info: &User) -> Result<(), ErrorCode> {
        parcel.write_i32(user_info.user_id);
        parcel.write_u64(user_info.sec_uid);
        parcel.write_i32(user_info.user_type as i32);
        
        self.write_credential_info(parcel, user_info.user_id)?;
        self.write_enrolled_info(parcel, user_info.user_id)?;
        
        Ok(())
    }

    fn write_credential_info(&self, parcel: &mut Parcel, user_id: i32) -> Result<(), ErrorCode> {
        let credential_filter: CredentialFilter = Box::new(move |cred: &Credential| {
            cred.user_id == user_id
        });
        
        match self.get_credential_list(credential_filter) {
            Ok(credentials) => {
                let credential_num = credentials.len() as u32;
                if credential_num == 0 || credential_num > MAX_USER_CREDENTIAL_NUM {
                    log_e!("credential_num is error, credential_num: {}", credential_num);
                    return Err(ErrorCode::GeneralError);
                }
                parcel.write_u32(credential_num);
                
                for credential in credentials {
                    parcel.write_u64(credential.credential_id.0);
                    parcel.write_u64(credential.template_id.0);
                    parcel.write_i32(credential.auth_type as i32);
                    parcel.write_u32(credential.executor_sensor_hint);
                    parcel.write_u32(credential.executor_matcher);
                    parcel.write_i32(credential.capability_level as i32);
                    parcel.write_i32(credential.credential_type as i32);
                    parcel.write_u64(credential.enrolled_sys_time);
                    parcel.write_u64(credential.abandon_sys_time);
                    parcel.write_u32(credential.abandon_flag as u32);
                    parcel.write_u32(credential.storage_type as u32);
                }
            }
            Err(ErrorCode::NotEnrolled) => {
                log_e!("credential is not found, user_id: {}", user_id);
                return Err(ErrorCode::GeneralError);
            }
            Err(e) => return Err(e),
        }
        
        Ok(())
    }

    fn write_enrolled_info(&self, parcel: &mut Parcel, user_id: i32) -> Result<(), ErrorCode> {
        let enrolled_filter: EnrolledIdFilter = Box::new(move |enrolled: &Enrolled| {
            enrolled.user_id == user_id
        });
        
        match self.get_enrolled_id_list(enrolled_filter) {
            Ok(enrolleds) => {
                let enrolled_num = enrolleds.len() as u32;
                if enrolled_num == 0 || enrolled_num > MAX_USER_CREDENTIAL_NUM {
                    log_e!("enrolled_num is error, enrolled_num: {}", enrolled_num);
                    return Err(ErrorCode::GeneralError);
                }
                parcel.write_u32(enrolled_num);
                
                for enrolled in enrolleds {
                    parcel.write_u64(enrolled.enrolled_id);
                    parcel.write_i32(enrolled.auth_type as i32);
                }
            }
            Err(ErrorCode::NotEnrolled) => {
                log_e!("enrolled is not found, user_id: {}", user_id);
                return Err(ErrorCode::GeneralError);
            }
            Err(e) => return Err(e),
        }
        
        Ok(())
    }

    fn generate_unique_id<'a, T, F, G>(&'a self, collection: F, id_extractor: G) -> Result<u64, ErrorCode> 
    where
        T: 'a,
        F: Fn() -> &'a [T] + 'a,
        G: Fn(&T) -> u64 + 'a,
    {
        let mut attempts = 0;
        const MAX_ATTEMPTS: usize = 100;
        loop {
            let mut random_bytes = [0u8; 8];
            CryptoEngineRegistry::get().secure_random(&mut random_bytes)
                .map_err(|_| ErrorCode::GeneralError)?;
            let random = u64::from_ne_bytes(random_bytes);
            
            let exists = collection().iter().any(|item| id_extractor(item) == random);
            if !exists {
                return Ok(random);
            }

            attempts += 1;
            if attempts >= MAX_ATTEMPTS {
                log_e!("random generate error");
                return Err(ErrorCode::GeneralError);
            }
        }
    }
}

impl UserDbManager for DefaultUserDbManager {
    fn add_user(&mut self, user_id: i32, user_type: UserType) -> Result<(), ErrorCode> {
        log_i!("add_user start");
        if self.user_infos.iter().any(|user| user.user_id == user_id) {
            log_i!("user is exist");
            return Ok(());
        }

        if let Ok(sec_uid) = self.generate_unique_sec_uid() {
            let user_state = UserState::UserStateInit;
            let new_user = User { user_id, sec_uid, user_type, user_state };
            self.user_infos.push(new_user);
            return Ok(());
        } else {
            log_e!("Failed to generate sec_uid");
            return Err(ErrorCode::GeneralError);
        }
    }

    fn get_user(&self, user_id: i32) -> Result<User, ErrorCode> {
        log_i!("get_user start");
        self.user_infos
            .iter()
            .find(|user| user.user_id == user_id)
            .cloned()
            .ok_or(ErrorCode::GeneralError)
    }

    fn remove_user(&mut self, user_id: i32) -> Result<(), ErrorCode> {
        log_i!("remove_user start");
        self.user_infos.retain(|user| user.user_id != user_id);
        self.credential_infos.retain(|cred| cred.user_id != user_id);
        self.enrolled_infos.retain(|enrolled| enrolled.user_id != user_id);
        return Ok(());
    }

    fn add_credential(&mut self, user_id: i32, credential_info: &Credential) -> Result<(), ErrorCode> {
        log_i!("add_credential start");
        if !self.user_infos.iter().any(|user| user.user_id == user_id) {
            log_e!("not find user");
            return Err(ErrorCode::GeneralError);
        }

        if self.credential_infos.iter().any(|cred|
            cred.user_id == user_id && cred.credential_id == credential_info.credential_id) {
            log_e!("credential is exist");
            return Err(ErrorCode::GeneralError);
        }

        let mut new_credential = credential_info.clone();
        new_credential.user_id = user_id;
        self.credential_infos.push(new_credential);
        return Ok(());
    }

    fn get_credential(&self, filter: CredentialFilter) -> Result<Credential, ErrorCode> {
        log_i!("get_credential start");
        self.credential_infos
            .iter()
            .find(|cred| filter(cred))
            .cloned()
            .ok_or(ErrorCode::NotEnrolled)
    }

    fn get_credential_list(&self, filter: CredentialFilter) -> Result<Vec<Credential>, ErrorCode> {
        log_i!("get_credential_list start");
        let mut credential_infos = Vec::new();
        for credential in &self.credential_infos {
            if filter(credential) {
                credential_infos.push(credential.clone());
            }
        }

        if credential_infos.is_empty() {
            Err(ErrorCode::NotEnrolled)
        } else {
            Ok(credential_infos)
        }
    }

    fn remove_credential(&mut self, credential_id: CredentialId) -> Result<(), ErrorCode> {
        log_i!("remove_credential start");
        let pos = self.credential_infos.iter().position(
            |cred| cred.credential_id == credential_id);
        match pos {
            Some(index) => {
                self.credential_infos.remove(index);
                Ok(())
            },
            None => Err(ErrorCode::NotEnrolled)
        }
    }

    fn remove_pin_credential(&mut self, user_id: i32) -> Result<(), ErrorCode> {
        log_i!("remove_pin_credential start");
        let original_count = self.credential_infos.len();
        self.credential_infos.retain(|cred| {(cred.user_id != user_id) || (cred.auth_type != AuthType::Pin &&
            cred.auth_type != AuthType::Face && cred.auth_type != AuthType::Fingerprint)});
        if self.credential_infos.len() < original_count {
            return Ok(());
        } else {
            Err(ErrorCode::GeneralError)
        }
    }

    fn add_enrolled_id(&mut self, user_id: i32, enrolled_info: &Enrolled) -> Result<(), ErrorCode> {
        log_i!("add_enrolled_id start");
        if self.enrolled_infos.iter().any(
            |enrolled| (enrolled.user_id == user_id && enrolled.auth_type == enrolled_info.auth_type)) {
            log_i!("enrolled is exist");
            return Ok(());
        }
        let mut new_enrolled = enrolled_info.clone();
        new_enrolled.user_id = user_id;
        self.enrolled_infos.push(new_enrolled);
        return Ok(());
    }

    fn remove_enrolled_id(&mut self, user_id: i32, auth_type: AuthType) -> Result<(), ErrorCode> {
        log_i!("remove_credential start");
        let pos = self.enrolled_infos.iter().position(
            |enrolled| (enrolled.user_id == user_id && enrolled.auth_type == auth_type));
        match pos {
            Some(index) => {
                self.enrolled_infos.remove(index);
                Ok(())
            },
            None => Err(ErrorCode::NotEnrolled)
        }
    }

    fn get_enrolled_id_list(&self, filter: EnrolledIdFilter) -> Result<Vec<Enrolled>, ErrorCode> {
        log_i!("get_credential_list start");
        let mut enrolled_infos = Vec::new();
        for enrolled in &self.enrolled_infos {
            if filter(enrolled) {
                enrolled_infos.push(enrolled.clone());
            }
        }

        if enrolled_infos.is_empty() {
            Err(ErrorCode::NotEnrolled)
        } else {
            Ok(enrolled_infos)
        }
    }

    fn get_enrolled_id(&self, user_id: i32, auth_type: AuthType) -> Result<u64, ErrorCode> {
        let enrolled_info = self.enrolled_infos.iter()
            .find(|info| info.user_id == user_id && info.auth_type == auth_type);
        match enrolled_info {
            Some(info) => Ok(info.enrolled_id),
            None => Err(ErrorCode::NotEnrolled),
        }
    }

    fn get_enrolled_list(&self, user_id: i32) -> Result<Vec<Enrolled>, ErrorCode> {
        let enrolled_list: Vec<Enrolled> = self.enrolled_infos.iter()
            .filter(|info| info.user_id == user_id)
            .cloned()
            .collect();

        if enrolled_list.is_empty() {
            Err(ErrorCode::NotFound)
        } else {
            Ok(enrolled_list)
        }
    }

    fn generate_unique_sec_uid(&self) -> Result<u64, ErrorCode> {
        self.generate_unique_id(
            move || self.user_infos.as_slice(),
            |user| user.sec_uid
        )
    }

    fn generate_unique_credential_id(&self) -> Result<u64, ErrorCode> {
        self.generate_unique_id(
            move || self.credential_infos.as_slice(),
            |credential| credential.credential_id.0
        )
    }

    fn generate_unique_enrolled_id(&self) -> Result<u64, ErrorCode> {
        self.generate_unique_id(
            move || self.enrolled_infos.as_slice(),
            |enrolled| enrolled.enrolled_id
        )
    }

    fn read_db(&mut self) -> Result<(), ErrorCode> {
        let user_infos: Vec<u8> = StorageIoRegistry::get().read(StorageType::Default, IDM_USER_INFO)?;
        if user_infos.is_empty() {
            log_i!("db is empty");
            return Ok(())
        }

        let mut parcel = Parcel::from(user_infos);
        let db_version = parcel.read_u32()?;
        if db_version > CURRENT_VERSION {
            log_e!("db_version is error, db_version:{}, current_version:{}", db_version, CURRENT_VERSION);
            return Err(ErrorCode::GeneralError);
        }
        let user_num = parcel.read_u32()?;
        if user_num == 0 {
            log_i!("no exist credential");
            return Ok(())
        }

        for _ in 0..user_num {
            let user_id = self.read_user_info(&mut parcel)?;
            let credential_num = parcel.read_u32()?;
            if credential_num == 0 || credential_num > MAX_USER_CREDENTIAL_NUM {
                log_i!("credential_num is error, credential_num: {}", credential_num);
                return Err(ErrorCode::GeneralError);
            }

            for _ in 0..credential_num {
                self.read_credential_info(user_id, db_version, &mut parcel)?;
            }

            let enrolled_num = parcel.read_u32()?;
            if enrolled_num == 0 || enrolled_num > MAX_USER_CREDENTIAL_NUM {
                log_e!("enrolled_num is error, enrolled_num: {}", enrolled_num);
                return Err(ErrorCode::GeneralError);
            }

            for _ in 0..enrolled_num {
                self.read_enrolled_info(user_id, &mut parcel)?;
            }
        }

        Ok(())
    }

    fn write_db(&mut self) -> Result<(), ErrorCode> {
        let mut parcel = Parcel::new();
        parcel.write_u32(CURRENT_VERSION);
        parcel.write_u32(self.user_infos.len() as u32);

        for user_info in &self.user_infos {
            self.write_user_info(&mut parcel, user_info)?;
        }

        StorageIoRegistry::get().write(StorageType::Default, IDM_USER_INFO, parcel.as_slice())?;
        Ok(())
    }

    fn reload_db(&mut self) -> Result<(), ErrorCode> {
        self.user_infos.clear();
        self.credential_infos.clear();
        self.enrolled_infos.clear();
        return self.read_db();
    }

    fn check_user_type_valid(&self, user_type: UserType) -> Result<bool, ErrorCode> {
        if user_type != UserType::Main && user_type != UserType::Sub && user_type != UserType::Private {
            log_e!("user type {:?} is invalid", user_type);
            return Ok(false);
        }
        Ok(true)
    }

    fn check_user_valid(&self, user_id: i32) -> Result<bool, ErrorCode> {
        let _ = self.get_user(user_id)?;
        let credential_filter: CredentialFilter = Box::new(move |cred: &Credential| {
            cred.user_id == user_id
        });

        if let Err(ErrorCode::NotEnrolled) = self.get_credential_list(credential_filter) {
            log_e!("credential is not found, user_id: {}", user_id);
            return Ok(false);
        }

        let enrolled_filter: EnrolledIdFilter = Box::new(move |enrolled: &Enrolled| {
            enrolled.user_id == user_id
        });

        if let Err(ErrorCode::NotEnrolled) = self.get_enrolled_id_list(enrolled_filter) {
            log_i!("enrolled is not found, user_id: {}", user_id);
            return Ok(false);
        }

        Ok(true)
    }

    fn check_credential_valid(&self, credential_id: CredentialId) -> Result<bool, ErrorCode> {
        let credential_filter: CredentialFilter = Box::new(move |cred: &Credential| {
            cred.credential_id == credential_id
        });

        let credential_info = match self.get_credential(credential_filter) {
            Ok(info) => info,
            Err(ErrorCode::NotEnrolled) => {
                log_e!("credential is not found, credential_id: {:?}", credential_id);
                return Err(ErrorCode::NotEnrolled);
            }
            Err(e) => return Err(e),
        };

        let credential_type = credential_info.credential_type;
        let enrolled_filter: EnrolledIdFilter = Box::new(move |enrolled: &Enrolled| {
            enrolled.auth_type as i32 == credential_type as i32
        });

        match self.get_enrolled_id_list(enrolled_filter) {
            Ok(_) => Ok(true),
            Err(ErrorCode::NotEnrolled) => {
                log_e!("enrolled is not found, auth_type: {:?}", credential_type);
                Ok(false)
            }
            Err(e) => Err(e),
        }
    }

    fn check_enrolled_valid(&self, user_id: i32, auth_type: AuthType) -> Result<bool, ErrorCode> {
        let enrolled_filter: EnrolledIdFilter = Box::new(move |enrolled: &Enrolled| {
            enrolled.user_id == user_id && enrolled.auth_type == auth_type
        });

        match self.get_enrolled_id_list(enrolled_filter) {
            Ok(_) => {
                let credential_filter: CredentialFilter = Box::new(move |cred: &Credential| {
                    cred.user_id == user_id && cred.credential_type as i32 == auth_type as i32
                });

                match self.get_credential_list(credential_filter) {
                    Ok(_) => Ok(true),
                    Err(ErrorCode::NotEnrolled) => {
                        log_e!(
                            "credential is not found user_id: {}, auth_type:{:?}", user_id, auth_type);
                        Ok(false)
                    }
                    Err(e) => Err(e),
                }
            }
            Err(ErrorCode::NotEnrolled) => {
                log_e!("enrolled is not found auth_type: {:?}", auth_type);
                Ok(false)
            }
            Err(e) => Err(e),
        }
    }

    fn get_all_user_id(&self) -> Result<Vec<i32>, ErrorCode> {
        if self.user_infos.is_empty() {
            log_e!("user_infos is null");
            return Err(ErrorCode::NotEnrolled);
        }
        Ok(self.user_infos.iter().map(|user| user.user_id).collect())
    }

    fn get_all_credential_id(&self) -> Result<Vec<CredentialId>, ErrorCode> {
        if self.credential_infos.is_empty() {
            log_e!("credential_infos is null");
            return Err(ErrorCode::NotEnrolled);
        }
        Ok(self.credential_infos.iter().map(|credential| credential.credential_id).collect())
    }

    fn get_all_enrolled_id(&self) -> Result<Vec<u64>, ErrorCode> {
        if self.enrolled_infos.is_empty() {
            log_e!("enrolled_infos is null");
            return Err(ErrorCode::NotEnrolled);
        }
        Ok(self.enrolled_infos.iter().map(|enrolled| enrolled.enrolled_id).collect())
    }

    fn get_user_type(&self, user_id: i32) -> Result<UserType, ErrorCode> {
        self.get_user(user_id).map(|user| user.user_type)
    }

    fn get_sec_uid(&self, user_id: i32) -> Result<u64, ErrorCode> {
        self.get_user(user_id).map(|user| user.sec_uid)
    }

    fn get_pin_sub_type(&self, user_id: i32) -> Result<i64, ErrorCode> {
        self.get_pin_credential(user_id).map(|cred| cred.credential_type as i64)
    }

    fn get_enrolled_sys_time(&self, user_id: i32) -> Result<i64, ErrorCode> {
        self.get_pin_credential(user_id).map(|cred| cred.enrolled_sys_time as i64)
    }

    fn get_credential_valid_peroid(&self, credential_id: CredentialId) -> Result<i64, ErrorCode> {
        let credential_filter: CredentialFilter = Box::new(move |cred: &Credential| {
            cred.credential_id == credential_id
        });

        let credential_info = match self.get_credential(credential_filter) {
            Ok(info) => info,
            Err(ErrorCode::NotFound) => {
                log_e!("credential is not found, credential_id: {:?}", credential_id);
                return Err(ErrorCode::NotFound);
            }
            Err(e) => return Err(e),
        };

        if credential_info.abandon_flag {
            let current_time = TimeKeeperRegistry::get().get_rtc_time()?;
            let valid_time = credential_info.abandon_sys_time.saturating_add(ABANDON_PIN_VALID_PERIOD);
            if valid_time <= current_time {
                return Ok(0)
            } else {
                return Ok((valid_time - current_time) as i64)
            };
        }

        let pin_expired_period = ConfigManagerRegistry::get().get_pin_expired_period()?;
        if pin_expired_period == NO_CHECK_PIN_EXPIRED_PERIOD {
            return Ok(0);
        }

        let current_time = TimeKeeperRegistry::get().get_ree_time()?;
        let valid_time = credential_info.enrolled_sys_time.saturating_add(pin_expired_period as u64);
        if current_time < credential_info.enrolled_sys_time || current_time >= valid_time {
            return Ok(0)
        } else {
            return Ok((valid_time - current_time) as i64)
        }
    }

    fn get_pin_credential(&self, user_id: i32) -> Result<Credential, ErrorCode> {
        let credential_filter: CredentialFilter = Box::new(move |cred: &Credential| {
            cred.user_id == user_id && cred.auth_type == AuthType::Pin && cred.abandon_flag == false
        });
        self.get_credential(credential_filter)
    }

    fn get_abandon_pin_credential(&self, user_id: i32) -> Result<Credential, ErrorCode> {
        let credential_filter: CredentialFilter = Box::new(move |cred: &Credential| {
            cred.user_id == user_id && cred.auth_type == AuthType::Pin && cred.abandon_flag == true
        });
        self.get_credential(credential_filter)
    }

    fn get_user_id_by_template_id(&self, tempalte_id: TemplateId) -> Result<i32, ErrorCode> {
        self.credential_infos
            .iter()
            .find(|cred| cred.template_id == tempalte_id)
            .map(|cred| cred.user_id)
            .ok_or(ErrorCode::NotFound)
    }

    fn get_credential_id_by_template_id(&self, tempalte_id: TemplateId) -> Result<CredentialId, ErrorCode> {
        self.credential_infos
            .iter()
            .find(|cred| cred.template_id == tempalte_id)
            .map(|cred| cred.credential_id)
            .ok_or(ErrorCode::NotFound)
    }

    fn check_specification(
        &self,
        user_id: i32,
        auth_type: AuthType,
        schedule_type: ScheduleType
    ) -> Result<(), ErrorCode> {
        let max_credential_number_per_user = AuthPolicyManagerRegistry::get()
            .get_auth_policy(auth_type)?
            .get_max_credential_number_per_user();

        if max_credential_number_per_user == 0 {
            log_e!("max number is 0, auth type {:?} not support", auth_type);
            return Err(ErrorCode::TypeNotSupport);
        }

        let credential_filter: CredentialFilter = Box::new(move |cred: &Credential| {
            cred.user_id == user_id && cred.auth_type == auth_type && cred.abandon_flag == false
        });
        let credential_list = self.get_credential_list(credential_filter)?;

        match schedule_type {
            ScheduleType::Enroll => {
                if credential_list.len() >= max_credential_number_per_user as usize {
                    log_e!("the enrolled authtype: {:?} has reached the upper limit {} of {}",
                        auth_type, credential_list.len(), max_credential_number_per_user);
                    return Err(ErrorCode::ExceedLimit);
                }
            },
            ScheduleType::Update => {
                if credential_list.len() < max_credential_number_per_user as usize {
                    log_e!("the update authtype: {:?} has not reached the required limit {} of {}",
                        auth_type, credential_list.len(), max_credential_number_per_user);
                    return Err(ErrorCode::NotEnrolled);
                }
            },
            ScheduleType::Abandon => {
                log_e!("not support");
                return Err(ErrorCode::TypeNotSupport);
            }
        }
        Ok(())
    }
}
